import { TextEncoder } from "./encoding";
import { commends } from "./commends";
import { Devices } from "./devices";

/**
 * ESC 链式蓝牙打印类
 * @param charset 初始化时，需定义打印机的编码，国产打印机基本是GBK
 * @constructor
 */
function Printer(charset){
    //gbk gb2312 ....
    charset = charset || 'gb2312';
    //转换为小写
    charset = charset.toLowerCase();
    //编码判断，然后使用不同编码转换
    if(charset === "gb2312" || charset === "gbk"){
        //GBK 打印机
        this.encoder = new TextEncoder("gb2312", {NONSTANDARD_allowLegacyEncoding: true});
    }else{
        //UFT8 打印机
        this.encoder = new TextEncoder("utf-8");
    }
    //清除缓存
    this.cleanQueue();
}
Printer.prototype = {
    /**
     * TextEncoder
     */
    encoder: null,
    /**
     * 打印数据原文
     */
    queue_data: [],
    /**
     * Array
     */
    queue: Array.from(commends.HARDWARE.HW_INIT),
    /**
     * 纸张字符宽度
     * 57mm纸打48mm宽，一般是32个字节宽度，即16个汉字或32个字符
     */
    width: 32,
    /**
     * 打印机每次写入支持的最大长度
     */
    buffer_chunk_size: 20,
    /**
     * 是否存在错误，如果存在错误，不会执行打印
     */
    error: false,
    //初始化
    init(){
        this.queue = Array.from(commends.HARDWARE.HW_INIT);
        this.queue_data = [];
        return this;
    },
    /**
     * 转换为uint8array
     * @param string
     * @return Array
     */
    encodeData(string){
        return this.encoder.encode(string);
    },
    /**
     * 加入需要打印的数据
     * @param data
     * @return {Printer}
     */
    pushQueue(data){
        //保存一下原文
        this.queue_data.push(data);
        //
        this.queue.push.apply(this.queue, Array.from(typeof data == "object" ? data : (typeof data == "function" ? data() : this.encodeData(data))));
        return this;
    },
    /**
     * 换行
     * @return {Printer}
     */
    newLine(){
        return this.pushQueue(commends.EOL)
    },
    /**
     * 设置纸张字符宽度，1个汉字2个宽度，其它1个宽度
     * @param width 字符宽度，非纸张的尺寸
     */
    setPaperWidth(width){
        this.width = width;
        return this;
    },
    /**
     * 设置打印流分片大小
     * @param byte
     * @return {Printer}
     */
    setBufferChunkSize(byte){
        this.buffer_chunk_size = byte || 20;
        return this;
    },
    /**
     * 设置对齐方式
     * @param align
     * @return {Printer}
     */
    setAlign(align){
        align = align || null;
        if(align !== null){
            align = align.toLowerCase();
            switch (align){
                case "right":
                case "rt":
                case "r":
                case "2":
                    this.pushQueue(commends.TEXT_FORMAT.TXT_ALIGN_RT);
                    break;
                case "center":
                case "ct":
                case "c":
                case "1":
                    this.pushQueue(commends.TEXT_FORMAT.TXT_ALIGN_LT);
                    break;
                default:
                    this.pushQueue(commends.TEXT_FORMAT.TXT_ALIGN_LT);
                    break;
            }
        }
        return this;
    },
    /**
     * 打印文字
     * @param text
     * @param align
     * @return {Printer}
     */
    printText(text, align){
        this.setAlign(align);
        return this.pushQueue(text);
    },
    /**
     * 连续打印相同字符
     * @param text
     * @param length
     * @return {Printer}
     */
    fillText(text, length){
        let text_string = "";
        text = text.toString();
        length = length || this.width;
        for(let i=0; i<length; i++){
            text_string += text;
        }
        return this.pushQueue(text_string);
    },
    /**
     * 打印二维码
     * @param data
     * @return {Printer}
     */
    printQRCode(data){

        return this;
    },
    /**
     * 从URL地址打印图片
     * @param url
     * @return {Printer}
     */
    printImageFromUrl(url){
        wx.getFileSystemManager().readFile({
            filePath: url,
            encoding: "base64",
            success : res => {
                let base64　= 'data:image/jpg;base64,' + res.data
                this.printImageFromBase64(base64);
            },
            fail : () => {
                wx.showModal({
                    title: "打印提醒",
                    content: "无法获取图片数据",
                    showCancel: false,
                    confirmText: "知道了"
                });
            }
        });
        return this;
    },
    /**
     * 从base64打印图片
     * @param base64
     * @return {Printer}
     */
    printImageFromBase64(base64){

        return this;
    },
    /**
     * 打印一个表格，注意，执行此处的时候，不可以再改变纸张宽度，否则可能无法打印，表格中仅限文字
     * 表格是从头打到，宽度不可超过设置的宽度，否则参数校验不通过，无法执行
     * @param list
     * @param width
     * @param celled
     * @return {Printer}
     */
    printTable(list, width, celled){
        let w = 0;
        for(let i = 0; i< width.length; i++){
            w += width[i];
            w += celled ? 1 : 0;
        }
        w += celled ? 1 : 0;
        if(w > this.width){
            this.error = true;
            wx.showModal({
                title: "打印提醒",
                content: "列表宽度超出限制"
            });
            return this;
        }
        //头
        if(celled){
            this.printText("+");
            for(let i=0; i<width.length; i++){
                this.fillText("-", width[i]).printText("+");
            }
        }
        for(let j=0; j<list.length; j++){
            let item = list[j];
            if(typeof item === "object"){
                //数组，多列
                let string_list = [];
                let max_line = 0;
                for(let k=0; k<width.length; k++){
                    let _str_arr = this.splitTableListChar(item[k] || "", width[k]);
                    string_list.push(_str_arr);
                    max_line = Math.max(max_line, _str_arr.length);
                }
                for(let l=0; l<width.length; l++){
                    //不足的填充空字符
                    string_list[l] = this.fillLineSpace(string_list[l], max_line, width[l]);
                }
                //得到一行
                let lines = [];
                for(let m=0; m<max_line; m++){
                    let _line = [];
                    if(celled){ _line.push(""); }
                    for(let n=0; n<width.length; n++){
                        _line.push(string_list[n][m]);
                    }
                    if(celled){ _line.push(""); }
                    lines.push(_line.join(celled ? "|" : ""));
                }
                //用换行符组合成多行文本
                this.newLine().printText(lines.join(commends.EOL));
            }else{
                //字符串，单列
                let _str_arr = this.splitTableListChar(item, width[0]);
                let lines = [];
                for(let j=0; j<_str_arr.length; j++){
                    lines.push((celled ? "|" : "") + _str_arr[j] + (celled ? "|" : ""));
                }
                //用换行符组合成多行文本
                this.newLine().printText(lines.join(commends.EOL));
            }
            //尾
            if(celled){
                this.newLine().printText("+");
                for(let i=0; i<width.length; i++){
                    this.fillText("-", width[i]).printText("+");
                }
            }
        }
        return this;
    },
    //开始打印
    exec(deviceId, callback){
        this.print(deviceId, callback)
    },
    print(deviceId, callback){
        let self = this;
        if(self.error){
            wx.showModal({
                title: "打印提醒",
                content: "打印参数存在错误"
            });
            return;
        }
        let pages = 0, success_page = 0;
        //加多一个换行  以免未打印最后一行
        this.newLine();
        Devices.writeCharacteristicValue(deviceId, (new Uint8Array(self.queue)).buffer, self.buffer_chunk_size, res => {
            pages = res.pages;
            if(!res.error){
                success_page++;
            }else{
                //打印失败
                if(typeof callback === "function"){
                    console.log(res);
                    callback({
                        error: 1,
                        message: res.message
                    });
                }
            }
            if(success_page === pages){
                //打印完成
                if(typeof callback === "function"){
                    callback({
                        error: 0,
                        message: 'success'
                    });
                }
            }
        });
    },
    //帮助方法
    //将字符按长度拆分成多个，如果是中文则占2个字符，该行不满字符的，自动填充空格字符
    splitTableListChar(string, len){
        let strings = string.split("");
        let result = [];
        let result_length = [];
        let line = "";
        let line_string_len = 0;
        for(let i=0; i<strings.length; i++){
            //判断字节
            let _len = /[^\x00-\xff]$/.test(strings[i]) ? 2 : 1;
            if((_len + line_string_len) > len){
                //超出了
                result.push(line);
                result_length.push(line_string_len);
                line_string_len = _len;
                line = strings[i];
            }else{
                //未超出
                line += strings[i].toString();
                line_string_len += _len;
                //一行满了
                if(line_string_len === len){
                    result.push(line);
                    result_length.push(line_string_len);
                    line_string_len = 0;
                    line = "";
                }
            }
        }
        //多余的
        if(line_string_len > 0){
            result.push(line);
            result_length.push(line_string_len);
        }
        //自动填充空格字符
        for(let j=0; j<result.length; j++){
            let _len = result_length[j];
            if(_len < len){
                //填充
                for(let k=0; k<len-_len; k++){
                    result[j] += " ";
                }
            }
        }
        return result;
    },
    //填满行数和空字符
    fillLineSpace(str_arr, line_len, space_len){
        let max_lines = line_len - str_arr.length;
        for(let i = str_arr.length; i <= max_lines; i++){
            str_arr[i] = "";
            for(let j=0;j<space_len;j++){
                str_arr[i] += " ";
            }
        }
        return str_arr;
    },
    //清除
    cleanQueue(){
        this.queue = Array.from(commends.HARDWARE.HW_INIT);
        this.queue_data = [];
        return this;
    }
};
exports.Printer = Printer;